package cn.ai.boot.config.PCF;

import java.io.*;
import java.util.*;
import java.util.regex.*;

public class PCFProcessor {
    private List<String> lines;
    private String filePath;
    private String plotConfiguration;
    private String unitsBore;
    private String fileName;
    private Long fileId;

    public String getPlotConfiguration() {
        return plotConfiguration;
    }

    public void setPlotConfiguration(String plotConfiguration) {
        this.plotConfiguration = plotConfiguration;
    }

    public Long getFileId() {
        return fileId;
    }

    public void setFileId(Long fileId) {
        this.fileId = fileId;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public String getUnitsBore() {
        return unitsBore;
    }

    public void setUnitsBore(String unitsBore) {
        this.unitsBore = unitsBore;
    }

    public List<String> getLines() {
        return lines;
    }


    public PCFProcessor(String filePath) throws IOException {
        this.filePath = filePath;
        this.lines = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                lines.add(line);
            }
        }
    }

    // 功能1：提取键值并去除空格
    public String getValueByKey(String key) {
        Pattern pattern = Pattern.compile("^" + key + "\\s+(\\S+)");
        for (String line : lines) {
            Matcher matcher = pattern.matcher(line);
            if (matcher.find()) {
                return matcher.group(1).trim();
            }
        }
        return null;
    }

    // 功能2：替换所有匹配标识，保留格式
    public void replaceAllIdentifiers(String oldId, String newId) {
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            // 使用正则表达式匹配标识符并替换，保留前后空格
            String updatedLine = line.replaceAll("(\\b)" + Pattern.quote(oldId) + "(\\b)", "$1" + newId + "$2");
            lines.set(i, updatedLine);
        }
    }

    // 功能3：获取匹配值的行号范围
    public List<int[]> getValueRanges(String value) {
        List<int[]> ranges = new ArrayList<>();
        Pattern valuePattern = Pattern.compile(".*" + Pattern.quote(value) + ".*");
        Pattern indentPattern = Pattern.compile("^\\s+.*");

        for (int i = 0; i < lines.size(); i++) {
            // 下标是从0开始
            if (valuePattern.matcher(lines.get(i)).matches()) {
                int start = findStartLine(i, indentPattern);
                int end = findEndLine(i, indentPattern) + 1;
                ranges.add(new int[]{start, end});
            }
        }
        return ranges;
    }

    private int findStartLine(int currentLine, Pattern indentPattern) {
        for (int i = currentLine - 1; i >= 0; i--) {
            if (!indentPattern.matcher(lines.get(i)).matches()) {
                return i + 1;
            }
        }
        return 0;
    }

    private int findEndLine(int currentLine, Pattern indentPattern) {
        for (int i = currentLine + 1; i < lines.size(); i++) {
            if (!indentPattern.matcher(lines.get(i)).matches()) {
                return i - 1;
            }
        }
        return lines.size() - 1;
    }

    public void saveToFile() throws IOException {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
            for (String line : lines) {
                writer.write(line);
                writer.newLine();
            }
        }
    }

    /**
     * 在指定的行号范围内替换所有匹配的旧标识符为新标识符
     *
     * @param oldId  要被替换的旧标识符
     * @param newId  替换后的新标识符
     * @param ranges 要替换的行号范围数组，每个元素为一个长度为2的数组，表示起始行和结束行（包含）
     */
    public void replaceIdentifiersInRange(String oldId, String newId, List<int[]> ranges) {
        for (int[] range : ranges) {
            int start = range[0];
            int end = range[1];

            for (int i = start; i <= end && i < lines.size(); i++) {
                String updatedLine = lines.get(i).replace(oldId, newId);
                lines.set(i, updatedLine);
            }
        }
    }


    /**
     * 在指定范围内精准替换某一行的键值对，保留原有空格格式
     *
     * @param key      要匹配的键名（如 "WELD-ATTRIBUTE1"）
     * @param newValue 新的值（如 "NEW_VALUE"）
     * @param ranges   行号范围数组
     */
    public void updateKeyValueInRange(String key, String newValue, List<int[]> ranges) {
        // 正则说明：
        // ^(\s*)             -> 匹配行首任意空格（缩进）
        // (key)              -> 匹配固定键名
        // (\s+)              -> 匹配一个或多个空格
        // (\S+)              -> 匹配原始值（非空格字符）
        // (\s*)$             -> 匹配行尾任意空格
        Pattern pattern = Pattern.compile("^(\\s*)" + Pattern.quote(key) + "(\\s+)(.+?)(\\s*)$");

        for (int[] range : ranges) {
            int start = range[0];
            int end = range[1];

            for (int i = start; i <= end && i < lines.size(); i++) {
                String line = lines.get(i);
                Matcher matcher = pattern.matcher(line);

                if (matcher.matches()) {
                    // 保留缩进、中间空格和后缀空格
                    String indent = matcher.group(1);
                    String spacing = matcher.group(2);
                    String suffix = matcher.group(4);

                    // 拼接新行：保留原有结构，只替换值部分
                    String updatedLine = indent + key + spacing + newValue + suffix;
                    lines.set(i, updatedLine);
                }
            }
        }
    }

    /**
     * 在指定范围的最后下行插入新的一行
     *
     * @param lineToInsert 插入的内容
     * @param ranges       行号范围数组
     */
    public void insertLineAfterRange(String lineToInsert, List<int[]> ranges) {
        for (int[] range : ranges) {
            int end = range[1];

            // 确保不会越界
            if (end + 1 <= lines.size()) {
                lines.add(end, lineToInsert);
            }
        }
    }


    /**
     * 在指定位置插入一行，并更新所有受影响的范围
     *
     * @param lineToInsert 要插入的内容
     * @param insertPos    插入的位置（从0开始）
     * @param ranges       当前的所有范围列表
     */
    public void insertLineAndUpdateRanges(String lineToInsert, int insertPos, List<int[]> ranges) {
        lines.add(insertPos, lineToInsert);

        // 更新所有后续范围
        for (int[] range : ranges) {
            if (range[0] > insertPos || (range[0] == insertPos && range[1] >= insertPos)) {
                range[0]++;
            }
            if (range[1] >= insertPos) {
                range[1]++;
            }
        }
    }


    /**
     * 下标都是0开始，获取行号需+1，开始为一个顶行的行号，结束为最后一个不顶行的行号
     */
    public List<int[]> getValueRanges2(String value) {
        List<int[]> ranges = new ArrayList<>();
        Pattern valuePattern = Pattern.compile(".*" + Pattern.quote(value) + ".*");

        for (int i = 0; i < lines.size(); i++) {
            if (valuePattern.matcher(lines.get(i)).matches()) {
                // 下标+1=定格的行号
                int start = findBlockStart(i);
                int end = findBlockEnd(i) - 1;// 由于下标0开始，此时就是行号
                ranges.add(new int[]{start, end});
            }
        }
        return ranges;
    }

    // 返回行号下标为0开始
    private int findBlockStart(int currentLine) {
        for (int i = currentLine; i >= 0; i--) {
            if (lines.get(i).trim().isEmpty() ||
                    !lines.get(i).startsWith(" ")) {
                return i;
            }
        }
        return 0;
    }

    // 返回行号下标为0开始
    private int findBlockEnd(int currentLine) {
        for (int i = currentLine; i < lines.size(); i++) {
            if (lines.get(i).trim().isEmpty() ||
                    !lines.get(i).startsWith(" ")) {
                return i;
            }
        }
        return lines.size() - 1;
    }


    /**
     * 在每个范围的末尾插入一行，并自动更新所有相关的范围信息
     *
     * @param lineToInsert 插入的新行内容
     * @param ranges       当前所有的范围列表
     */
    public void insertLineAtRangeEnds(String lineToInsert, List<int[]> ranges) {
        for (int i = 0; i < ranges.size(); i++) {
            int[] currentRange = ranges.get(i);
            int insertPos = currentRange[1] + 1;

            lines.add(insertPos, lineToInsert);

            // 更新当前范围的结束行号
            currentRange[1]++;

            // 更新后续所有范围
            for (int j = i + 1; j < ranges.size(); j++) {
                int[] r = ranges.get(j);
                if (r[0] > insertPos || (r[0] == insertPos)) {
                    r[0]++;
                }
                if (r[1] >= insertPos) {
                    r[1]++;
                }
            }
        }
    }


    /**
     * 在每个范围的头部和尾部插入指定的新行，并自动更新所有相关的范围信息
     *
     * @param lineToInsertAtStart 插入到范围头部的新行内容
     * @param lineToInsertAtEnd   插入到范围尾部的新行内容
     * @param ranges              当前所有的范围列表
     */
    public void insertLinesAtRangeStartAndEnd(String lineToInsertAtStart, String lineToInsertAtEnd, List<int[]> ranges) {
        for (int i = 0; i < ranges.size(); i++) {
            int[] currentRange = ranges.get(i);

            // 在范围头部插入新行
            int insertPosStart = currentRange[0] + 1;
            lines.add(insertPosStart, lineToInsertAtStart);

            // 更新当前范围的起始和结束行号
            currentRange[0]++;
            currentRange[1]++;

            // 更新后续所有范围
            for (int j = i + 1; j < ranges.size(); j++) {
                int[] r = ranges.get(j);
                if (r[0] >= insertPosStart) {
                    r[0]++;
                }
                if (r[1] >= insertPosStart) {
                    r[1]++;
                }
            }

            // 在范围尾部插入新行
            int insertPosEnd = currentRange[1] + 1;
            lines.add(insertPosEnd, lineToInsertAtEnd);

            // 更新当前范围的结束行号
            currentRange[1]++;

            // 更新后续所有范围
            for (int j = i + 1; j < ranges.size(); j++) {
                int[] r = ranges.get(j);
                if (r[0] > insertPosEnd || r[0] == insertPosEnd) {
                    r[0]++;
                }
                if (r[1] >= insertPosEnd) {
                    r[1]++;
                }
            }
        }
    }

    /**
     * 在每个范围的头部下一行和尾部插入指定的新行，并自动更新所有相关的范围信息
     *
     * @param lineToInsertAtHeaderNext 插入到范围头部下一行的新行内容
     * @param lineToInsertAtEnd        插入到范围尾部的新行内容
     * @param ranges                   当前所有的范围列表
     */
    public void insertLinesAtHeaderNextAndEnd(String lineToInsertAtHeaderNext, String lineToInsertAtEnd, List<int[]> ranges) {
        for (int i = 0; i < ranges.size(); i++) {
            int[] currentRange = ranges.get(i);

            int headerInsertPos = currentRange[0] + 1;

            // 插入头部下一行
            lines.add(headerInsertPos, lineToInsertAtHeaderNext);

            // 更新当前范围及后续范围（插入位置在 headerInsertPos）
            currentRange[1]++; // 当前范围结束行更新
            updateRangesAfterInsert(ranges, headerInsertPos, i);
            int endInsertPos = currentRange[1] + 1;

            // 插入尾部
            lines.add(endInsertPos, lineToInsertAtEnd);

            // 更新当前范围及后续范围（插入位置在 endInsertPos）
            currentRange[1]++; // 当前范围结束行更新
            updateRangesAfterInsert(ranges, endInsertPos, i);
        }
    }

    /**
     * 插入后更新所有受影响的后续范围
     *
     * @param ranges       当前所有范围
     * @param insertPos    插入位置
     * @param currentIdx   当前处理的范围索引
     */
    private void updateRangesAfterInsert(List<int[]> ranges, int insertPos, int currentIdx) {
        for (int j = currentIdx + 1; j < ranges.size(); j++) {
            int[] r = ranges.get(j);
            if (r[0] > insertPos || (r[0] == insertPos)) {
                r[0]++;
            }
            if (r[1] >= insertPos) {
                r[1]++;
            }
        }
    }

    /**
     * 在文件末尾插入多行数据
     *
     * @param linesToInsert 要插入的多行内容
     */
    public void appendLinesToFileEnd(List<String> linesToInsert) {
        lines.addAll(linesToInsert);
    }


    /**
     * 获取指定关键字的最大编号值
     *
     * @param key 要查找的关键字（如 "COMPONENT-IDENTIFIER"）
     * @return 最大的编号值
     */
    public int getMaxIdentifierByKey(String key) {
        int maxId = 0;
        Pattern pattern = Pattern.compile("^\\s*" + Pattern.quote(key) + "\\s+(\\d+)");

        for (String line : lines) {
            Matcher matcher = pattern.matcher(line);
            if (matcher.matches()) {
                int id = Integer.parseInt(matcher.group(1));
                if (id > maxId) {
                    maxId = id;
                }
            }
        }

        return maxId;
    }
}
